/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "Console.h"
#include "Config.h"
#include "Launcher.h"

#include <algorithm>

/////////////////////////////////////////////////////////////////////////////
//
// Console Namespace
//

void Console::InitializeGLXConsole( )
{
	Console::SetForegroundBackgroundColor( CONSOLE_COLOR_WHITE, CONSOLE_COLOR_BLACK );
	SetConsoleTitle( "GameLauncherX ( GLX ) - 1.0 <Author: ijikix>" );
	printf( "             %s\n             %s\n\n",
			"GameLauncherX (GLX) 1.0 - Created by ijikix@gmail.com",
			"www.MapleStory.Nexon.net" );
	Console::ResetForegroundBackgroundColor( );
	PrintProgressTable( );
	Console::EnableDebugPrivilege( true );
}

void Console::PrintText( __in std::string Text, __in int ForegroundColor, __in int BackgroundColor )
{
	SetForegroundBackgroundColor( ForegroundColor, BackgroundColor );
	printf( Text.c_str( ) );
}

void Console::PrintProgressTable( )
{
	printf( "current progress                         result\n%s\n",
			"=======================================  ======================================" );
}

void Console::PrintProgressInfo( __in std::string Text, __in_opt int ForegroundColor, __in_opt int BackgroundColor )
{
	FixPrintProgressInput( Text );
	SetForegroundBackgroundColor( ForegroundColor, BackgroundColor );
	Sleep( 100 );

	if( Text.length( ) > 39 )
		printf( "%s...  ", Text.substr( 0, 36 ).c_str( ) );
	else if( Text.length( ) < 39 && Text.length( ) > 0 )
	{
		while( Text.length( ) != 39 )
			Text += " ";
		printf( "%s  ", Text.c_str( ) );
	}
	else
		printf( "%s  ", Text.c_str( ) );
}

void Console::PrintProgressResult( __in int Result,
								   __in_opt std::string Text,
								   __in_opt int ForegroundColor,
								   __in_opt int BackgroundColor )
{
	FixPrintProgressInput( Text );
	SetForegroundBackgroundColor( ForegroundColor, BackgroundColor );

	if( Result == CONSOLE_PROGRESS_RESULT_FAILED )
		printf( "failed\n" );
	else if( Result == CONSOLE_PROGRESS_RESULT_SUCCEEDED )
		printf( "succeeded\n" );
	else if( Result == CONSOLE_PROGRESS_RESULT_FAILED_ERROR )
	{
		if( Text.length( ) > 23 )
			printf( "failed, error: %s...\n", Text.substr( 0, 20 ).c_str( ) );
		else
			printf( "failed, error: %s\n", Text.c_str( ) );
	}
	else if( Result == CONSOLE_PROGRESS_RESULT_SUCCEEDED_INFO )
	{
		if( Text.length( ) > 27 )
			printf( "succeeded: %s...\n", Text.substr( 0, 24 ).c_str( ) );
		else
			printf( "succeeded: %s\n", Text.c_str( ) );
	}
	else if( Result == CONSOLE_PROGRESS_RESULT_CUSTOM )
	{
		if( Text.length( ) > 27 )
			printf( "%s...\n", Text.substr( 0, 24 ).c_str( ) );
		else
			printf( "%s\n", Text.c_str( ) );
	}
	else
		printf( "unknown\n" );
}

void Console::FixPrintProgressInput( __inout std::string &Input )
{
	Input.erase( remove( Input.begin( ), Input.end( ), '\t' ), Input.end( ) );
	Input.erase( remove( Input.begin( ), Input.end( ), '\n' ), Input.end( ) );
	Input.erase( remove( Input.begin( ), Input.end( ), '\r' ), Input.end( ) );
}

void Console::SetForegroundBackgroundColor( __in int ForegroundColor, __in int BackgroundColor )
{
	SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), ForegroundColor + ( BackgroundColor * 16 ) );
}

void Console::ResetForegroundBackgroundColor( )
{
	SetForegroundBackgroundColor( CONSOLE_COLOR_DEFAULT_FOREGROUND_COLOR, CONSOLE_COLOR_DEFAULT_BACKGROUND_COLOR );
}

void ClearScreen( )
{
	COORD						ScreenCoordinate = { 0, 0 };
	DWORD						CharsWritten	= NULL;
	CONSOLE_SCREEN_BUFFER_INFO	ConsoleScreenBufferInfo;
	HANDLE						ConsoleHandle = GetStdHandle( STD_OUTPUT_HANDLE );

	if( !GetConsoleScreenBufferInfo( ConsoleHandle, &ConsoleScreenBufferInfo ) )
      return;
	if( !FillConsoleOutputCharacter( ConsoleHandle,
                                     0x20,
                                     ConsoleScreenBufferInfo.dwSize.X * ConsoleScreenBufferInfo.dwSize.Y,
                                     ScreenCoordinate,
                                     &CharsWritten ) )
	  return;

	if( !GetConsoleScreenBufferInfo( ConsoleHandle, &ConsoleScreenBufferInfo ) )
      return;
	if( !FillConsoleOutputAttribute( ConsoleHandle, 
                                     ConsoleScreenBufferInfo.wAttributes,
                                     ConsoleScreenBufferInfo.dwSize.X * ConsoleScreenBufferInfo.dwSize.Y,
									 ScreenCoordinate,
                                     &CharsWritten ) )
	  return;
	SetConsoleCursorPosition( ConsoleHandle, ScreenCoordinate );
}

void Console::ShowWindow( __in bool Hide )
{
	ShowWindow( GetConsoleWindow( ), Hide ); 
}

void Console::Quit( __in int Reason )
{
	if( Reason == CONSOLE_QUIT_REASON_SUCCEEDED )
		printf( "\nGLX has succeeded, please enter the return key to quit.\n" );
	else if( Reason == CONSOLE_QUIT_REASON_FAILED )
		printf( "\nGLX has failed, please enter the return key to quit.\n" );
	else if( Reason == CONSOLE_QUIT_REASON_ERROR )
		printf( "\nGLX has encountered an error, enter the return key to quit.\n" );
	else if( Reason == CONSOLE_QUIT )
		exit( 0 );
	else /* unknown */
		printf( "\nplease enter the return key to quit.\n" );

	std::cin.get( );
	exit( Reason );
}

void Console::SetWindowSize( __in int X, __in int Y )
{
	RECT Rect;
	GetWindowRect( GetConsoleWindow( ), &Rect );
	MoveWindow( GetConsoleWindow( ), Rect.left + 5, Rect.top + 5, X, Y, TRUE );
}

void Console::GhostMode( __in bool Enable, __in int TransparencyLevel )
{
	SetWindowLong( GetConsoleWindow( ), GWL_EXSTYLE, GetWindowLong( GetConsoleWindow( ),GWL_EXSTYLE ) ^WS_EX_LAYERED );
	if( Enable )
		if( TransparencyLevel <= 10 && TransparencyLevel <= 255 )
			SetLayeredWindowAttributes( GetConsoleWindow( ), RGB( 0, 0, 0 ), TransparencyLevel, LWA_ALPHA );
		else
			SetLayeredWindowAttributes( GetConsoleWindow( ), RGB( 0, 0, 0 ), 200, LWA_ALPHA );
	else
		SetLayeredWindowAttributes( GetConsoleWindow( ), RGB( 0, 0, 0 ), 255, LWA_ALPHA );
}

BOOL Console::EnableDebugPrivilege( bool Enable )
{
	bool	Success = false;
	HANDLE	TokenHandle = NULL;

	Console::PrintProgressInfo( "enabling debug privilege" );

	do
	{
		if( !OpenProcessToken( GetCurrentProcess( ), TOKEN_ADJUST_PRIVILEGES, &TokenHandle ) ) {
			Console::PrintProgressResult( CONSOLE_PROGRESS_RESULT_FAILED_ERROR, "'OpenProcessToken'" );
			break;
		}

		TOKEN_PRIVILEGES TokenPrivileges;
		TokenPrivileges.PrivilegeCount = 1;
		if( !LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &TokenPrivileges.Privileges[ 0 ].Luid ) ) {
			Console::PrintProgressResult( CONSOLE_PROGRESS_RESULT_FAILED_ERROR, "'LookupPrivilegeValue'" );
            break;
        }
		
		TokenPrivileges.Privileges[ 0 ].Attributes = Enable ? SE_PRIVILEGE_ENABLED : 0;
		if( !AdjustTokenPrivileges( TokenHandle, FALSE, &TokenPrivileges, sizeof( TokenPrivileges ), NULL, NULL ) )
        {
			Console::PrintProgressResult( CONSOLE_PROGRESS_RESULT_FAILED_ERROR, "'AdjustTokenPrivileges'" );
            break;
        }
		Success = true;
	} while ( 0 );

	if( TokenHandle != NULL )
		if( !CloseHandle( TokenHandle ) )
			Console::PrintProgressResult( CONSOLE_PROGRESS_RESULT_FAILED_ERROR, "close token handle" );

	Console::PrintProgressResult( CONSOLE_PROGRESS_RESULT_SUCCEEDED );
	return Success;
}